﻿@using System.Globalization
@inject IConfiguration _configuration
@inject IChatService _chatService
@inject ChatState _chatState
@inject NavigationManager _navigationManager
@inject ISnackbar Snackbar

@implements IAsyncDisposable

<MudDrawer @bind-Open="IsDrawerOpen" Elevation="1" ClipMode="DrawerClipMode.Never" Variant="DrawerVariant.Persistent" Anchor="Anchor.Left" Width="480px">
    <MudContainer Class="d-flex pa-0 overflow-x-hidden" Style="height: 100%; width: 100%;">
        <div class="d-flex flex-column" style="width: 100%;">
            <div class="d-flex flex-1 w-100 overflow-hidden">

                @*------------ left column ------------ *@
                <div id="drawer-left-column" class="d-flex flex-column align-items-center pa-1" style="width:72px; background-color:@(_IsDarkModeEnabled ? "#1e1f22" : "#d6d3d1");">
                    <AssistantPickerButton AvatarUrl="@_chatState.SelectedAssistant?.AvatarUrl" OnAvatarClick="OnAvatarClick" />
                    <div class="d-flex flex-column align-items-center flex-grow-1 fixed mb-2" style="bottom: 6px">
                        <MudTooltip Text="New chat" Arrow="true" Placement="Placement.Right" >
                            <MudFab OnClick="CreateNewChat" Size="Size.Medium" Color="Color.Primary" StartIcon="@Icons.Material.Filled.Add" Class="mb-6 ml-2" />
                        </MudTooltip>
                        
                        <MudDivider Class="mx-auto" Style="width:70%;" />

                        <MudTooltip Text="Actions" Arrow="true" Placement="Placement.Right">
                            <MudFab OnClick="OnActionsClick" Size="Size.Medium" Color="Color.Default" StartIcon="@Icons.Material.Filled.AutoAwesome" IconSize="Size.Large" Class="mt-6 ml-2" />
                        </MudTooltip>

                        <MudTooltip Text="Settings" Arrow="true" Placement="Placement.Right">
                            <MudIconButton OnClick="OnSettingsClick" Style="margin-left: 2px;" Size="Size.Large" Icon="@Icons.Material.Filled.Settings" Class="mt-4" />
                        </MudTooltip >
                    </div>
                </div>
                <MudDivider Vertical="true" />

                @*------------ right column ------------ *@
                <div id="drawer-right-column" class="p-3 flex-grow-1 overflow-y-auto w-100 h-100" style="background-color:@(_IsDarkModeEnabled ? "#27272f" : "#e7e5e4");">
                    <div class="d-flex flex-column h-100">
                        <MudText Typo="Typo.h5" Class="mx-auto mt-3 mb-2">Stellar Chat</MudText>
                        <MudDivider />
                        <MudText Typo="Typo.h6" Class="mt-2 ml-4">Chat History</MudText>
                        <div class="flex-grow-1 overflow-y-auto w-100 h-100 mt-2">
                            <MudTextField Class="pl-4 pr-4 pb-4 custom-placeholder" T="string" @bind-Value="SearchText" TextChanged="HandleSearchTextChanged" Immediate="true" Clearable="true" Placeholder="Explore previous conversations" Margin="Margin.Dense" Variant="Variant.Outlined" Adornment="Adornment.End" AdornmentIcon="@Icons.Material.Filled.Search" />
                            <MudDivider />
                            <MudList Clickable="true" @bind-SelectedItem="SelectedItem" @bind-SelectedValue="SelectedValue" Color="@(_IsDarkModeEnabled ? Color.Tertiary : Color.Dark)">
                                @foreach (var group in ChatSessions.OrderByDescending(x => x.CreatedAt).GroupBy(a => a.CreatedAt.ToString("yyyy-MM-dd", CultureInfo.CurrentCulture)))
                                {
                                    <MudListSubheader Class="pb-1">
                                        @group.Key
                                    </MudListSubheader>
                                    @foreach (var chatSession in group)
                                    {
                                        <ChatHistoryItem ChatSessionItem="@chatSession"
                                                         OnChangeTitle="ChangeChatSessionTitle"
                                                         OnDeleteChat="DeleteChatSession" />
                                    }
                                }
                            </MudList>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </MudContainer>
</MudDrawer>

<style>
    .no-hover:hover {
            background-color: transparent !important;
        }
</style>

@code
{
    [CascadingParameter]
    private bool _IsDarkModeEnabled { get; set; }

    [Parameter]
    public bool IsDrawerOpen { get; set; }

    [Parameter]
    public EventCallback OnAvatarClick { get; set; }

    [Parameter]
    public EventCallback OnSettingsClick { get; set; }

    [Parameter]
    public EventCallback OnActionsClick { get; set; }

    private MudListItem? SelectedItem { get; set; }
    private object? SelectedValue { get; set; }

    public string SearchText { get; set; } = string.Empty;

    public List<ChatSessionResponse> ChatSessions { get; set; } = new();

    private CancellationTokenSource? _cts;
    private StringBuilder _textStreaming = new();
    private HubConnection? _hubConnection;
    private string HubUrl => $"{_configuration["api:url"]}/hub";

    protected override async Task OnInitializedAsync()
    {
        _hubConnection = new HubConnectionBuilder()
            .WithUrl(HubUrl)
            .WithAutomaticReconnect()
            .Build();

        _hubConnection.On<Guid, string>(nameof(IChatHub.ReceiveUpdateChatTitle), async (chatId, message) =>
        {
            _textStreaming.Append(message);

            var chatSession = ChatSessions.SingleOrDefault(x => x.Id == chatId);

            if (chatSession is not null)
            {
                ChatSessions[ChatSessions.IndexOf(chatSession)] = chatSession with { Title = _textStreaming.ToString() };
                StateHasChanged();
            }

            await Task.CompletedTask;
        });

        Console.WriteLine("Starting connection...");

        await _hubConnection.StartAsync();

        Console.WriteLine($"Connection state: {_hubConnection.State}");

        _chatState.IsNewChatPendingChanged += StateHasChanged;
        _chatState.ChatIdChanged += SelectNewCreatedChat;
        _chatState.SelectedAssistantChanged += StateHasChanged;
        _chatState.AssignedAssistantChanged += StateHasChanged;
        _chatState.AssistantUpdated += async () => await LoadChatSessions();

        await LoadChatSessions();
        SelectChatHistoryItem(_chatState.ChatId);
    }

    private async Task ChangeChatSessionTitle(ChangeTitleInfo changeTitleInfo)
    {
        var (chatId, newTitle) = changeTitleInfo;

        var response = await _chatService.ChangeChatSessionTitle(chatId, newTitle!);

        if(!response.Succeeded)
        {
            ShowSnackbar("Failed to change chat title. Please try again.", Severity.Error);
        }

        var chatSession = ChatSessions.SingleOrDefault(x => x.Id == chatId);

        if (chatSession is not null)
        {
            ChatSessions[ChatSessions.IndexOf(chatSession)] = chatSession with { Title = newTitle! };
        }

        ShowSnackbar($"Chat title was updated successfully!", Severity.Success);
    }

    private async Task DeleteChatSession(ChatSessionResponse chatSession)
    {
        var response = await _chatService.DeleteChatSession(chatSession.Id);

        if (response.Succeeded)
        {
            if (IsCurrentlySelectedChat(chatSession.Id))
            {
                DeselectChatHistoryItem();
                _chatState.SetChatId(Guid.Empty);
                _navigationManager.NavigateTo("/");
            }
        }
        else
        {
            ShowSnackbar("Failed to delete a chat. Please try again.", Severity.Error);
        }

        ChatSessions.Remove(chatSession);
        ShowSnackbar($"Chat '{chatSession.Title}' was deleted successfully!", Severity.Success);
        await LoadChatSessions();
    }

    private async Task LoadChatSessions()
    {
        var response = await _chatService.BrowseChatSessions();
        var chatSessions = response.Value;

        ChatSessions = chatSessions.Items.ToList();
    }

    private async Task HandleSearchTextChanged(string searchText)
    {
        _cts?.Cancel();
        _cts = new CancellationTokenSource();

        try
        {
            await Task.Delay(500, _cts.Token);

            var response = await _chatService.SearchChatSessions(searchText);
            var chatSessions = response.Value;

            ChatSessions = chatSessions.Items.ToList();
        }
        catch (TaskCanceledException)
        {
        }
    }

    private void CreateNewChat()
    {
        DeselectChatHistoryItem();
        _textStreaming.Clear();
        _chatState.SetChatId(Guid.Empty);
        _navigationManager.NavigateTo("/");
    }

    public async ValueTask DisposeAsync()
    {
        _chatState.IsNewChatPendingChanged -= StateHasChanged;
        _chatState.ChatIdChanged -= SelectNewCreatedChat;
        _chatState.SelectedAssistantChanged -= StateHasChanged;
        _chatState.AssignedAssistantChanged -= StateHasChanged;
        _chatState.AssistantUpdated -= async () => await LoadChatSessions();

        await Task.CompletedTask;
    }

    private async void SelectNewCreatedChat()
    {
        if (_chatState.IsNewChatPending)
        {
            await LoadChatSessions();
            _chatState.SetIsNewChatPending(false);
        }

        SelectChatHistoryItem(_chatState.ChatId);
    }

    private void SelectChatHistoryItem(Guid chatId)
    {
        var chatSessionToSelect = ChatSessions.SingleOrDefault(chat => chat.Id == chatId);

        if (chatSessionToSelect is not null)
        {
            _chatState.SetAssignedAssistant(chatSessionToSelect!.AssignedAssistant);

            SelectedItem = new MudListItem
            {
                Value = chatSessionToSelect.Id
            };

            SelectedValue = chatSessionToSelect.Id;
            StateHasChanged();
        }
    }

    private bool IsCurrentlySelectedChat(Guid chatId)
        => IsAnyChatSelected() && SelectedValue!.Equals(chatId);

    private bool IsAnyChatSelected()
        => (SelectedItem, SelectedValue) is (not null, not null);

    private void DeselectChatHistoryItem()
    {
        SelectedItem = null;
        SelectedValue = null;
    }

    private void ShowSnackbar(string message, Severity severity)
    {
        Snackbar.Configuration.PositionClass = Defaults.Classes.Position.TopRight;

        Snackbar.Add(message, severity, options =>
        {
            options.HideTransitionDuration = 100;
        });
    }
}
